자바를 사용해서 보안적인 프로그램을 개발하려면 :: 자바네트워크I/O[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

자바네트워크I/O
[1]
등록일:2008-03-06 13:15:00 (0%)
작성자:
제목:자바를 사용해서 보안적인 프로그램을 개발하려면
자바를  사용해서  보안적인  프로그램을  개발하려면  솔직히  자바를  배운  후  첫  단계는  자바  보안에  대한  두  개의  기본  텍스트인  Gong  [1999]  와  McGraw  [1999]  를  읽는  것이다  (두번째의  경우  특히  7.1  절을  보라).  또한  http://java.sun.com/security/seccodeguide.html  에서  썬이  게시한  보안  코드  지침들을  보아야  한다.  자바의  보안  모델을  설명하는  일련의  슬라이드들은  http://www.dwheeler.com/javasec  에서  얻을  수  있다.  또한  McGraw  [1998]  을  볼  수도  있다.

명백히  많은  것들은  개발하고  있는  애플리케이션의  유형에  의존하는데  클라이언트측에서  사용하기  위한  자바  코드는  서버측  코드와는  전혀  다른  환경  (과  신뢰  모델)  을  갖고  있다.  물론  일반적인  원리는  적용된다.  예를  들어  신뢰되지  않은  출처로부터  온  모든  입력을  검사  및  필터링해야  한다.  그러나  자바에는  밑부분에서  논의될  조심해야  할  어떤  숨겨진  입력  또는  잠재적  입력들이  있다.  Johnathan  Nightingale  [2000]  은  자바  프로그래밍에서  많은  문제들을  요약하고  있는  재미있는  문서를  작성했다:

        ...자바  프로그래밍에서  큰  문제는  상속에  신경을  써야한다는  것이다.  부모,  인터페이스  또는  부모의  인터페이스로부터  메쏘드를  상속한다면  코드에  보안  구멍을  열  것을  각오하는  것이다.  

다음은  Gong  [1999],  McGraw  [1999],  썬의  길잡이와  저자의  경험에  기초한  중요한  약간의  지침들이다.

      1.

            public  필드  또는  변수를  사용하지  마라;  이들은  private  으로  선언하고  이들의  접근성을  제한할  수  있도록  이들에  대한  접근자를  제공해라.
      2.

            메쏘드를  private  으로  만들지  않을  확실한  이유가  없다면  private  으로  만들어라  (그렇지  않다면  이를  문서화해라).  이러한  non-private  메쏘드들은  tainted  데이타를  받을  수도  있기  때문에  어쨌든  이들을  보호하기  위해  미리  준비하지  않았다면  그들  자신을  보호해야  한다.
      3.

            JVM  은  애플릿과는  반대로  애플리케이션에서  런타임시  접근  변경자  (예,  private)  를  실제  적용하지  않을  수도  있다.  2000년  11월  7일  "Secure  Programming"  메일링  리스트에서  이를  지적한  John  Steven  (Cigital  Inc.)  에  고맙게  생각한다.  문제는  이  모두가  접근을  요청하는  클래스가  어떤  클래스  로더와  함께  적재되느냐에  의존한다는  것이다.  클래스가  신뢰된  클래스  로더  (null/primordial  클래스  로더를  포함해)  와  함께  적재되면  접근  검사는  접근을  허용하는  "TRUE"  를  반환한다.  예를  들어  이는  적어도  썬의  1.2.2  VM  과  함께  작동하는데  그러나  다른  버전에서는  작동하지  않을  수도  있다:

                  1.

                        public  필드를  갖는  victim  클래스  (V)  를  작성해  컴파일해라.
                  2.

                        이  필드에  접근하는  attack  클래스  (A)  를  작성해  컴파일해라.
                  3.

                        V  의  public  필드를  private  으로  변경한  후  다시  컴파일해라.
                  4.

                        A  를  실행시켜라  -  이는  V  의  (지금은  private)  필드에  접근할  것이다.

            그러나  애플릿의  경우는  상황이  다르다.  A  를  애플릿으로  변환하고  애플릿뷰어  또는  브라우저로  이를  실행시키면  A  의  클래스  로더는  더이상  신뢰된  (또는  null)  클래스  로더가  아니다.  따라서  코드는  클래스  A  로부터  V.secret  필드를  접근하려  하고  있다는  메시지와  함께  java.lang.IllegralAccessError  를  발생시킬  것이다.
      4.

            정적  필드  변수의  사용을  피해라.  이러한  변수는  클래스  (인스턴스가  아닌)  에  소속된  것으로  모든  다른  클래스가  클래스의  위치를  찾을  수  있다.  그  결과  정적  필드  변수는  모든  다른  클래스가  찾을  수  있으며  따라서  정적  필드  변수를  안전하게  하는  것은  더욱  어렵다.
      5.

            잠재적으로  악의있는  코드에  가변  객체를  절대로  반환하지  마라  (코드가  이를  변경하기로  결정할  수도  있기  때문에).  배열은  가변적  (물론  배열의  내용들은  가변적이  아닐지라도)  임을  주목해라.  따라서  기밀을  다루는  데이타를  갖는  내부  배열에  대한  참조를  반환하지  마라.
      6.

            절대로  사용자가  제공한  가변  객체  (객체의  배열을  포함해)  를  직접적으로  저장하지  마라.  그렇지  않으면  사용자가  객체를  보안적인  코드에  건네주고  보안적인  코드가  객체를  검사하게  한  후  보안적인  코드가  데이타를  사용하려고  하는  동안  데이타를  변경할  수  있다.  배열을  내부적으로  저장하기  전에  복제  (clone)  하고  이에  주의해라  (사용자가  작성한  복제  루틴에  주의해라).
      7.

            초기화에  의존하지  마라.  초기화되지  않은  객체를  할당하는  몇몇  방법이  있다.
      8.

            확실한  이유가  없다면  모든  것을  final  로  만들어라.  클래스  또는  메쏘드가  final  이  아니라면  공격자가  이를  위험하고  예기치  못한  방식으로  확장하려고  할  수  있다.  물론  이는  보안적이지만  확장성을  잃음을  주목해라.
      9.

            보안을  위해  패키지  유효  범위  (scope)  에  의존하지  마라.  java.lang  와  같은  약간의  클래스들은  디폴트로  닫혀  있으며  몇몇  JVM  (Java  Virtual  Machine)  은  다른  패키지들을  닫도록  한다.  그렇지  않으면  자바  클래스들은  닫혀있지  않은  상태이다.  따라서  공격자가  패키지안에  새로운  클래스를  도입해서  이를  사용해  보호하고  있다고  생각하는  것에  접근할  수  있다.
    10.

            내부  클래스를  사용하지  마라.  내부  클래스가  바이트  코드로  변환될  때  내부  클래스는  패키지  내의  모든  클래스에  접근할  수  있는  클래스로  변환된다.  더욱  바람직하지  않은  것은  내부  클래스를  갖고  있는  (enclosing)  클래스의  private  필드가  소리없이  non-private  가  되어  내부  클래스에  의한  접근을  허용한다.
    11.

            권한을  최소화해라.  가능한  어떠한  특별한  허가권도  요구하지  마라.  McGraw  는  더  나아가서  모든  코드에  서명하지  말라고  권하고  있다  ;  저자는  더  나아가서  코드에  서명하지만  (따라서  사용자들은  단지  이  전송자  목록에  의해  서명된  코드만  실행시키기로  정할  수  있다)  sandbox  권한셋  이상을  필요로  하지  않는  프로그램을  작성하라고  말한다.  더욱  많은  권한을  가져야  한다면  코드를  특별히  엄하게  감사해라.
    12.

            코드에  서명해야  한다면  이를  모두  한  아카이브  파일에  놓아라.  여기서  McGraw  [1999]  를  인용하는  것이  최선이다.

                    이  규칙의  목적은  공격자가  악의있는  클래스와  각자가  서명한  클래스들중  일부를  링크시키거나  절대로  함께  사용되지  않아야  하는  서명된  클래스들을  함께  링크시키는  새로운  애플릿  또는  라이브러리를  구축하는  mix-and-match  공격을  수행하지  못하도록  하는  것이다.  일단의  클래스들을  함께  서명함으로써  이  공격을  더  어렵게  만들어라.  기존의  코드  서명  시스템은  mix-and-match  공격을  예방하기에  부적절한데  따라서  이  규칙이  이러한  공격을  완전히  예방할  수는  없다.  그러나  하나의  아카이브를  사용하는  것이  나쁜  영향을  미칠  수는  없다.  

    13.

            클래스를  복제  불가능하게  만들어라.  자바의  객체  복제  메카니즘은  공격자가  생성자들  중  어떤  것도  실행시키지  않고도  클래스를  인스턴스화할  수  있도록  한다.  클래스를  불제  불가능하게  만들기  위해서는  단지  각  클래스에  다음  메쏘드를  정의해라:

            public  final  void  clone()  throws  java.lang.CloneNotSupportedException  {
                  throw  new  java.lang.CloneNotSupportedException();
                  }

            클래스를  정말  복제가능하게  만들  필요가  있다면  공격자가  클론  메쏘드를  재정의하지  못하도록  취할  수  있는  약간의  보호  조치가  있다.  각자의  클론  메쏘드를  정의한다면  단지  이를  final  로  정의해라.  그렇지  않으면  다음을  추가함으로써  최소한  클론  메쏘드가  악의적으로  재정의되는  것을  예방할  수  있다:

            public  final  void  clone()  throws  java.lang.CloneNotSupportedException  {
                super.clone();
                }

    14.

            클래스를  unserializeable  로  만들어라.  직렬화는  공격자가  객체뿐만  아니라  private  부분들의  내부  상태를  볼  수  있도록  한다.  이를  예방하기  위해  클래스에  다음  메쏘드를  추가해라:

            private  final  void  writeObject(ObjectOutputStream  out)
                throws  java.io.IOException  {
                      throw  new  java.io.IOException("Object  cannot  be  serialized");
                }

            직렬화가  무방한  경우라도  반드시  시스템  자원에  대한  직접적인  핸들과  주소  공간에  대한  정보를  포함하는  필드에  대해  transient  키워드를  사용해라.  그렇지  않으면  클래스를  deserializing  함으로써  부적절한  접근을  허용할  수도  있다.  또한  기밀을  다루는  정보를  transient  로  식별하려고  할  수도  있다.

            클래스에  대해  각자의  직렬화  메쏘드를  정의한다면  배열을  취하는  모든  DataInput/DataOutput  에  내부  배열을  전달해서는  안된다.  근본적  이유는  모든  DataInput/DataOutput  메쏘드들은  재정의될  수  있기  때문이다.  Serializable  클래스가  DataOutput  (write(byte  []  b))  메쏘드에  직접적으로  private  배열을  보낸다면  공격자는  private  배열을  접근  및  변경할  수  있도록  서브  클래스  ObjectOutputStream  을  사용해  write(byte  []  b)  메쏘드를  재정의할  수  있다.  디폴트  serialization  은  DataInput/DataOutput  바이트  배열  메쏘드에  private  바이트  배열  필드를  드러내지  않음을  주목해라.
    15.

            클래스를  undeserializeable  하게  만들어라.  클래스가  serializeable  하지  않더라도  deserializeable  일  수  있다.  공격자는  자신이  선택한  값을  갖는  클래스의  인스턴스에  우연히  deserialize  할  수  있는  바이트  시퀀스를  생성할  수  있다.  다른  말로  deserialization  은  일종의  public  생성자로  공격자가  객체  상태를  선택할  수  있도록  하는데  이는  명백히  위험한  연산이다.  이를  예방하기  위해  클래스에  다음  메쏘드를  추가해라:

            private  final  void  readObject(ObjectInputStream  in)
                throws  java.io.IOException  {
                    throw  new  java.io.IOException("Class  cannot  be  deserialized");
                }

    16.

            이름으로  클래스를  비교하지  마라.  결국  공격자는  동일한  이름을  갖는  클래스를  정의할  수  있으며  주의하지  않는다면  이러한  클래스에  부적당한  권한을  허용함으로써  혼동을  일으킬  수  있다.  다음은  객체가  주어진  클래스를  갖는지를  결정하는데  있어  잘못된  방법의  예이다:

                if  (obj.getClass().getName().equals("Foo"))  {

            두  객체가  정확히  동일한  클래스를  갖는지  결정할  필요가  있다면  대신  양측에  모두  getClass()  를  사용하고  ==  연산자를  사용해  비교해라.  이는  다음과  같이  사용해야  한다:

                if  (a.getClass()  ==  b.getClass())  {

            객체가  주어진  클래스이름을  갖는지  정확히  결정할  필요가  있다면  현재  클래스의  ClassLoader  의  현재  이름공간을  사용하는지를  확인할  필요가  있다.  따라서  다음  포맷을  사용할  필요가  있을  것이다:

                if  (obj.getClass()  ==  this.getClassLoader().loadClass("Foo"))  {

            이  지침은  McGraw  와  Felten  에  의한  것으로  아주  훌륭한  지침인데  저자는  어쨌든  클래스  값들의  비교를  가능한  피하는  것이  언제나  좋은  생각이라고  추가할  것이다.  물론  이를  전혀  할  필요가  없도록  클래스  메쏘드와  인터페이스를  설계하려는  것이  더욱  확실한  방법이다.  그러나  이  방법이  늘  실용적이지는  않으며  따라서  이러한  요령을  아는  것이  중요하다.
    17.

            암호화키,  패스워드  또는  알고리듬  같은  비밀을  코드  또는  데이타에  저장하지  마라.  악의가  있는  JVM  들은  빨리  이  데이타를  볼  수  있다.  코드  obfuscation  (애매화)  이  실제로  심각한  공격자들로부터  코드를  숨기지는  않는다.  
[본문링크] 자바를 사용해서 보안적인 프로그램을 개발하려면
[1]
코멘트(이글의 트랙백 주소:/cafe/tb_receive.php?no=2391
작성자
비밀번호

 

SSISOCommunity

[이전]

Copyright byCopyright ⓒ2005, SSISO Community All Rights Reserved.